package com.mmzs.springboot.s00.application.opc;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.common.JISystem;
import org.jinterop.dcom.core.*;
import org.openscada.opc.dcom.common.*;
import org.openscada.opc.dcom.common.impl.OPCCommon;
import org.openscada.opc.dcom.da.OPCDATASOURCE;
import org.openscada.opc.dcom.da.OPCITEMDEF;
import org.openscada.opc.dcom.da.OPCITEMRESULT;
import org.openscada.opc.dcom.da.OPCITEMSTATE;
import org.openscada.opc.dcom.da.impl.OPCGroupStateMgt;
import org.openscada.opc.dcom.da.impl.OPCItemMgt;
import org.openscada.opc.dcom.da.impl.OPCServer;
import org.openscada.opc.dcom.da.impl.OPCSyncIO;

import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.mmzs.springboot.s00.application.opc.BaseConfiguration.*;

/**
 * 同步读取Item
 *
 * @author Freud
 */
public class UcomItemIdBatch {

    public static void batchWork() throws Exception {
        JISystem.setAutoRegisteration(true);

        /**
         * Session获取
         */
        JISession _session = JISession.createSession(getEntryValue(CONFIG_DOMAIN), getEntryValue(CONFIG_USERNAME),
                getEntryValue(CONFIG_PASSWORD));

        final JIComServer comServer = new JIComServer(JIClsid.valueOf(getEntryValue(CONFIG_CLSID)),
                getEntryValue(CONFIG_HOST), _session);

        final IJIComObject serverObject = comServer.createInstance();

        OPCServer server = new OPCServer(serverObject);

        /**
         * 添加一个Group的信息
         */
        OPCGroupStateMgt group = server.addGroup("test", true, 100, 1234, 60, 0.0f, 1033);

        testItems(server, group, getStringItemIds());

        // clean up
        server.removeGroup(group, true);
//		server.removeGroup(group, false);
    }

    private static void showError(final OPCCommon common, final int errorCode) throws JIException {
        System.out.println(String.format("Error (%X): '%s'", errorCode, common.getErrorString(errorCode, 1033)));
    }

    private static void showError(final OPCServer server, final int errorCode) throws JIException {
        showError(server.getCommon(), errorCode);
    }

    private static boolean dumpOPCITEMRESULT(final KeyedResultSet<OPCITEMDEF, OPCITEMRESULT> result) {
        int failed = 0;
        for (final KeyedResult<OPCITEMDEF, OPCITEMRESULT> resultEntry : result) {
            /*System.out.println("==================================");
            System.out.println(String.format("Item: '%s' ", resultEntry.getKey().getItemID()));

            System.out.println(String.format("Error Code: %08x", resultEntry.getErrorCode()));*/
            if (!resultEntry.isFailed()) {
                /*System.out.println(String.format("Server Handle: %08X", resultEntry.getValue().getServerHandle()));
                System.out.println(String.format("Data Type: %d", resultEntry.getValue().getCanonicalDataType()));
                System.out.println(String.format("Access Rights: %d", resultEntry.getValue().getAccessRights()));
                System.out.println(String.format("Reserved: %d", resultEntry.getValue().getReserved()));*/
            } else {
                failed++;
            }
        }
        return failed == 0;
    }

    private static String[] getStringItemIds() {

        String itemIds = getEntryValue(CONFIG_ITEMIDS);
		/*List<String> itemIds_list = Arrays.asList(itemIds.split(",")).stream().map(s -> s.trim())
				.collect(Collectors.toList());
		String[] need_ids = itemIds_list.toArray(new String[itemIds_list.size()]);*/
        String[] need_ids = itemIds.split(",");
        return need_ids;
    }

    private static void testItems(final OPCServer server, final OPCGroupStateMgt group, final String... itemIDs)
            throws IllegalArgumentException, UnknownHostException, JIException {

        final OPCItemMgt itemManagement = group.getItemManagement();
        final List<OPCITEMDEF> items = new ArrayList<OPCITEMDEF>(itemIDs.length);
        for (final String id : itemIDs) {
            final OPCITEMDEF item = new OPCITEMDEF();
            item.setItemID(id);
            item.setClientHandle(new Random().nextInt());
            items.add(item);
        }

        final OPCITEMDEF[] itemArray = items.toArray(new OPCITEMDEF[0]);

        System.out.println("Validate");
        KeyedResultSet<OPCITEMDEF, OPCITEMRESULT> result = itemManagement.validate(itemArray);
        if (!dumpOPCITEMRESULT(result)) {
            return;
        }

        // now add them to the group
        System.out.println("Add");
        result = itemManagement.add(itemArray);
        if (!dumpOPCITEMRESULT(result)) {
            return;
        }

        // get the server handle array
        final Integer[] serverHandles = new Integer[itemArray.length];
        for (int i = 0; i < itemArray.length; i++) {
            serverHandles[i] = new Integer(result.get(i).getValue().getServerHandle());
        }

        // set them active
        System.out.println("Activate");
        final ResultSet<Integer> resultSet = itemManagement.setActiveState(true, serverHandles);
       /* for (final Result<Integer> resultEntry : resultSet) {
            System.out.println(
                    String.format("Item: %08X, Error: %08X", resultEntry.getValue(), resultEntry.getErrorCode()));
        }*/

        // set client handles
        System.out.println("Set client handles");
        final Integer[] clientHandles = new Integer[serverHandles.length];
        for (int i = 0; i < serverHandles.length; i++) {
            clientHandles[i] = i;
        }
        itemManagement.setClientHandles(serverHandles, clientHandles);

        System.out.println("Create async IO 2.0 object");
        // OPCAsyncIO2 asyncIO2 = group.getAsyncIO2 ();
        // connect handler

        System.out.println("attach");
        final EventHandler eventHandler = group.attach(new DumpDataCallback());

        // sleep
        try {
            System.out.println("Waiting...");
            Thread.sleep(1 * 500);
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }

        eventHandler.detach();

        // sync IO - read
        final OPCSyncIO syncIO = group.getSyncIO();
        // OPCAsyncIO2 asyncIO2 = group.getAsyncIO2 ();
        /*
         * System.out.println ( "attach..enable" ); asyncIO2.setEnable ( true );
         * System.out.println ( "attach..refresh" ); asyncIO2.refresh ( (short)1, 1 );
         */

        final KeyedResultSet<Integer, OPCITEMSTATE> itemState = syncIO.read(OPCDATASOURCE.OPC_DS_DEVICE, serverHandles);
        StringBuilder alldata = new StringBuilder();
        //alldata.append(getEntryValue(CONFIG_ITEMIDS)).append(",").append("writer_time");
        for (final KeyedResult<Integer, OPCITEMSTATE> itemStateEntry : itemState) {
            final int errorCode = itemStateEntry.getErrorCode();
            /*System.out.println(
                    String.format("Server ID: %08X, Value: %s, Timestamp: %d/%d (%Tc), Quality: %d, Error: %08X",
                            itemStateEntry.getKey(), itemStateEntry.getValue().getValue(),
                            itemStateEntry.getValue().getTimestamp().getHigh(),
                            itemStateEntry.getValue().getTimestamp().getLow(),
                            itemStateEntry.getValue().getTimestamp().asCalendar(),
                            itemStateEntry.getValue().getQuality(), errorCode));*/
            if (errorCode != 0) {
                showError(server, errorCode);
            }
//			((OPCITEMRESULT) itemStateEntry.getValue()).getCanonicalDataType();
//			itemState.ge
            int resultType = itemStateEntry.getValue().getValue().getType();
            String resultValue = getRealValue(resultType, itemStateEntry.getValue().getValue());
           // System.out.println("------type类型--------" + itemStateEntry.getValue().getValue().getType());
            alldata.append(",").append(resultValue);
        }
        alldata.append(",").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        // WriteDataIntoCsv.Array2CSV(alldata.toString(), "test.csv");
        String resultData = alldata.toString().substring(1).replaceAll("\\[\\[", "").replaceAll("\\]\\]", "");
        WriteDataIntoCsv.saveAsFileWriter(resultData, generateFile(),false);
        // set them inactive
        System.out.println("In-Active");
        itemManagement.setActiveState(false, serverHandles);

        // finally remove them again
        System.out.println("Remove");
        itemManagement.remove(serverHandles);
    }
    //按年月天小时分生成文件
    private static File generateFile() {
        Calendar now = Calendar.getInstance();
        String path = new StringBuilder("/").append(now.get(Calendar.YEAR)).append("/")
                .append(now.get(Calendar.MONTH) + 1 + "").append("/").append(now.get(Calendar.DAY_OF_MONTH)).append("/")
                .append(now.get(Calendar.HOUR_OF_DAY)).append("/").toString();
        //.append(now.get(Calendar.MINUTE))
        File fRe = new File(path);
        if (!fRe.exists()) {
            fRe.mkdirs();
            //fResult.createNewFile();
        }
        File fResult = new File(new StringBuilder(path).append(now.get(Calendar.MINUTE)).toString()+".csv");
        if (!fResult.exists()) {
            try {
                fResult.createNewFile();
//                alldata.append().append(",").append("writer_time");
                String head = getEntryValue(CONFIG_ITEMIDS).replaceAll(getEntryValue(CONFIG_GROUDID),"");
                WriteDataIntoCsv.saveAsFileWriter(new StringBuilder(head).append(",").append("writer_time").toString(), generateFile(),true);
                //alldata.append(getEntryValue(CONFIG_ITEMIDS)).append(",").append("writer_time");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fResult;
    }


    private static String getRealValue(int type, JIVariant valueResult) {

        String sweetValue = new String();
        if (type == JIVariant.VT_I2) {
            short n = 0;
            try {
                n = valueResult.getObjectAsShort();
            } catch (JIException e) {
                e.printStackTrace();
            }
            sweetValue = n + "";
            //System.out.println("-----类型值： " + n);
        }
        // 如果读到是类型的值type=3 对应的西门子(DINT)Double Word java类型int
        if (type == JIVariant.VT_I4) {
            Integer n = 0;
            try {
                n = valueResult.getObjectAsInt();
            } catch (JIException e) {
                e.printStackTrace();
            }
            sweetValue = n + "";
            System.out.println("-----类型值： " + n);
        }
        // 如果读到是字符串类型的值type=4,对应西门子的类型是real,java类型float
        if (type == JIVariant.VT_R4) { // 字符串的类型是4
            Float n = null;
            try {
                n = valueResult.getObjectAsFloat();
            } catch (JIException e) {
                e.printStackTrace();
            } // 按字符串读取
            sweetValue = n + "";
            System.out.println("-----类型值： " + n);
        }
        // 如果读到是字符串类型的值type=11,对应西门子的类型是boolean,java类型boolean
        if (type == JIVariant.VT_BOOL) { // 字符串的类型是11
            Boolean n = null;
            try {
                n = valueResult.getObjectAsBoolean();
            } catch (JIException e) {
                e.printStackTrace();
            } // 按字符串读取
            sweetValue = n + "";
            System.out.println("-----类型值： " + n);
        }
        // 如果读到是字符串类型的值type=17,对应西门子的类型是byte,java类型byte
        if (type == JIVariant.VT_UI1) { // 字符串的类型是17
            Number n = null;
            try {
                n = valueResult.getObjectAsUnsigned().getValue();
                System.out.println(
                        " ---------- " + valueResult.getObjectAsUnsigned().getValue());
            } catch (JIException e) {
                e.printStackTrace();
            } // 按字符串读取
            sweetValue = n + "";
            System.out.println("-----类型值： " + n);
        }
        // 如果读到是字符串类型的值type=18,对应西门子的类型是word,java类型short
        if (type == JIVariant.VT_UI2) { // 字符串的类型是18
            Short n = null;
            try {
                n = valueResult.getObjectAsUnsigned().getValue().shortValue();
                System.out.println(" ---------- "
                        + valueResult.getObjectAsUnsigned().getValue().shortValue());
            } catch (JIException e) {
                e.printStackTrace();
            } // 按字符串读取
            sweetValue = n + "";
            System.out.println("-----类型值： " + n);
        }
        return sweetValue;
    }

}
